#============================================================
#	Simple Platform Controller
#============================================================
# @datetime: 2022-2-28 12:03:06
#============================================================

##  简单的平台角色控制器
class_name SimplePlatformController
extends MoveController


##  跳跃
signal jumped
## 落下
signal falled


##  控制的宿主
@export
var host : CharacterBody2D
##  输入缓冲时间。在这个时间内按下跳跃，在落在地面上后自动进行跳跃
@export_range(0.0, 1.0, 0.001, "or_greater")
var buffer_time : float = 0.1
## 土狼时间。离开地面后，在这个时间内仍可以进行跳跃
@export_range(0.0, 1.0, 0.001, "or_greater")
var grace_time : float = 0.1
## 启用跳跃功能
@export
var jump_enabled := true
## 跳跃高度
@export
var jump_height : float = 0.0
# 是否启用重力
@export
var gravity_enabled := true
##  重力下降速率（每帧下降速度）
@export_range(0.0, 60.0, 0.001, "or_greater")
var gravity_rate : float = 1.0
## 最大重力下降速度
@export
var gravity_max : float = 0.0
## 判定为落下的要求超出的速度，即：下落速度超出这个值，则会判定为落下状态。
@export
var determine_fall : float = 10.0


# 缓冲跳跃计时器
var __buffer_jump_timer := Timer.new()
# 土狼时间计时器
var __grace_timer := Timer.new()

# 跳跃高度
var __jump_height := 0.0
# 是否已经发出落下的信号
var __emited_fall_signal : bool = true


#============================================================
#   Set/Get
#============================================================
func set_property_by_dict(data: Dictionary):
	for prop in data:
		if prop in self:
			set(prop, data[prop])

##  在土狼时间内可以跳跃
func is_can_jump():
	return __grace_timer.time_left > 0

## 是否落下
func is_fall():
	return host.get_last_motion().y > determine_fall * get_physics_process_delta_time()

## 是否在跳跃
func is_jump():
	return host.get_last_motion().y < 0


#============================================================
#   内置
#============================================================
func _ready():
	__buffer_jump_timer.wait_time = buffer_time
	__buffer_jump_timer.one_shot = true
	__buffer_jump_timer.timeout.connect(set.bind('_jump', false))
	add_child(__buffer_jump_timer)
	
	__grace_timer.wait_time = grace_time
	__grace_timer.one_shot = true
	add_child(__grace_timer)


#============================================================
#   自定义
#============================================================
#(override)
func _move(delta: float):
	# 重力
	if gravity_enabled:
		if host.is_on_floor():
			motion_velocity.y = 0.0
		else:
			motion_velocity.y = lerpf(motion_velocity.y, gravity_max, gravity_rate * get_physics_process_delta_time() )
	else:
		motion_velocity.y = 0
	
	# 碰到天花板
	if host.is_on_ceiling() and motion_velocity.y < 0:
		motion_velocity.y = 0
	
	# 开始跳跃
	if __buffer_jump_timer.time_left > 0:
		if (host.is_on_floor()
			or __grace_timer.time_left > 0
		):
			_jump()
	else:
		# 土狼时间
		if host.is_on_floor():
			__grace_timer.start(grace_time)
	
	# 移动
	motion_velocity.x = __move_speed * __direction.x
	host.velocity = motion_velocity
	host.move_and_slide()
	motion_velocity = host.get_last_motion() / get_physics_process_delta_time()
	moved.emit(motion_velocity)
	
	# 是否落下
	if not host.is_on_floor():
		if not __emited_fall_signal:
			if is_fall():
				__emited_fall_signal = true
				falled.emit()
	else:
		__emited_fall_signal = false
	
	# 移动后
	if __previous_direction.x == 0:
		__move_speed = lerpf(__move_speed, 0.0, friction * get_physics_process_delta_time() )
	if __move_speed == 0.0:
		self.__moving = false
	__previous_direction = Vector2(0,0)


#(override)
func move_direction(direction: Vector2):
	move_left_right(direction.x)
	if direction.y < 0:
		jump()


#(override)  
func move_vector(velocity: Vector2):
	_update_state(Vector2(sign(velocity.x), 0))
	motion_velocity.x = velocity.x
	if velocity.y < 0:
		jump(velocity.y)

##  控制跳跃
func _jump():
	motion_velocity.y = -__jump_height
	__buffer_jump_timer.stop()
	__grace_timer.stop()
	jumped.emit()


##  更改方向
func change_direction(dir):
	if dir is float or dir is int:
		update_direction(Vector2(dir, 0))
	elif dir is Vector2:
		update_direction(dir)
	else:
		assert(false, "参数必须是 float、int、Vector2 类型 ")


##  左右移动
## @left_right  
func move_left_right(left_right: float):
	__previous_direction = Vector2(sign(left_right), 0)
	_update_state(__previous_direction)


##  跳跃
## @height  跳跃高度
## @force  强制跳跃
func jump(height: float = INF, force: bool = false):
	if jump_enabled:
		__emited_fall_signal = false
		__jump_height = (height if height != INF else jump_height)
		if force:
			_jump()
		else:
			__buffer_jump_timer.start()

